package ezy.lite.util;

import android.util.Log;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

public class Shell {

    private static final String COMMAND_SU       = "su";
    private static final String COMMAND_SH       = "sh";
    private static final String COMMAND_EXIT     = "exit\n";
    private static final String COMMAND_LINE_END = "\n";


    /** 判断手机是否root，不弹出root请求框  */
    public static boolean isRooted() {
        String binPath = "/system/bin/su";
        if (new File(binPath).exists() && isExecutable(binPath)) {
            return true;
        }
        String xBinPath = "/system/xbin/su";
        if (new File(xBinPath).exists() && isExecutable(xBinPath)) {
            return true;
        }
        return false;
    }

    private static boolean isExecutable(String filePath) {
        Process p = null;
        try {
            p = Runtime.getRuntime().exec("ls -l " + filePath);
            // 获取返回内容
            BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String str = in.readLine();
            Log.i("isRooted", str);
            if (str != null && str.length() >= 4) {
                char flag = str.charAt(3);
                if (flag == 's' || flag == 'x') {
                    return true;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            destroy(p);
        }
        return false;
    }

    private static void destroy(Process p) {
        try {
            if (p != null) {
                p.exitValue();
            }
        } catch (IllegalThreadStateException e) {

            try {
                p.destroy();
            } catch (Exception ex) {

            }
        }
    }


    public static Result exec(String command, boolean isRoot) {
        return exec(new String[]{command}, isRoot, true);
    }
    public static Result exec(String command, boolean isRoot, boolean isNeedResultMsg) {
        return exec(new String[]{command}, isRoot, isNeedResultMsg);
    }


    public static Result exec(List<String> commands, boolean isRoot) {
        return exec(commands == null ? null : commands.toArray(new String[]{}), isRoot, true);
    }
    public static Result exec(List<String> commands, boolean isRoot, boolean isNeedResultMsg) {
        return exec(commands == null ? null : commands.toArray(new String[]{}), isRoot, isNeedResultMsg);
    }

    public static Result exec(String[] commands, boolean isRoot) {
        return exec(commands, isRoot, true);
    }
    public static Result exec(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
        Result result = new Result(-1);
        if (commands == null || commands.length == 0) {
            return result;
        }
        Process process = null;
        DataOutputStream os = null;
        try {
            process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
            os = new DataOutputStream(process.getOutputStream());
            for (String command : commands) {
                if (command == null) {
                    continue;
                }
                // donnot use os.writeBytes(commmand), avoid chinese charset error
                os.write(command.getBytes());
                os.writeBytes(COMMAND_LINE_END);
                os.flush();
            }
            os.writeBytes(COMMAND_EXIT);
            os.flush();

            result.code = process.waitFor();

            // get command code
            if (isNeedResultMsg) {
                result.output = IoUtil.readString(process.getInputStream());
                result.error = IoUtil.readString(process.getErrorStream());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            result.code = -2;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IoUtil.close(os);
            destroy(process);
        }
        return result;
    }

    public static class Result {

        public int code;
        public String output;
        public String error;

        public Result(int code) {
            this.code = code;
        }

        public Result(int code, String output, String error) {
            this.code = code;
            this.output = output;
            this.error = error;
        }

        @Override
        public String toString() {
            return "\ncode ==> " + code + "\noutput ==> " + output + "\n error ==> " + error + "\n";
        }
    }
}